﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace WWWSiteHelper
{
    public class TabObservator
    {
        private TabControl tabControl;
        private readonly Dictionary<TabPage, AbstractFile> tabToAbstractFile = new Dictionary<TabPage, AbstractFile>();
        private readonly Dictionary<AbstractFile, TabPage> fileToTabPage = new Dictionary<AbstractFile, TabPage>();
        private readonly Dictionary<TabPage, bool> wasChanged = new Dictionary<TabPage, bool>();

        public EventHandler TextChanged { get; set; }
        public KeyEventHandler KeyUp { get; set; }
        public KeyEventHandler KeyDown { get; set; }

        public TextBox CurrentTextBox { get { return tabToTextBox(tabControl.SelectedTab); } }
        public bool AnyUnsaved
        {
            get
            {
                return wasChanged.Any(x => x.Value);
            }
        }

        public TabObservator(TabControl tabControl)
        {
            this.tabControl = tabControl;
            tabControl.Selected += tabControl_Selected;
            TextChanged = (x, y) => { };
            KeyUp = (x, y) => { };
            KeyDown = (x, y) => { };
        }

        public void CloseTab()
        {
            TabPage t = tabControl.SelectedTab;
            if (t == null)
                return;
            fileToTabPage.Remove(tabToAbstractFile[t]);
            tabToAbstractFile.Remove(t);
            wasChanged.Remove(t);
            tabControl.TabPages.Remove(t);
        }

        public void SetContext(AbstractFile file)
        {
            TabPage tabPage;
            if (!fileToTabPage.TryGetValue(file, out tabPage))
            {
                Control box = makeTextBox(file);
                String headline = file.Name + "." + TypeConverter.getString(file.Type);
                tabPage = makeTabPage(headline, box);
                tabControl.TabPages.Add(tabPage);
                tabToAbstractFile[tabPage] = file;
                fileToTabPage[file] = tabPage;
                wasChanged[tabPage] = false;
            }
            tabControl.SelectedTab = tabPage;
            TextChanged.Invoke(CurrentTextBox, null);
        }

        public void SaveCurrentContext()
        {
            TabPage tabPage = tabControl.SelectedTab;
            if (tabPage == null)
                return;
            saveTab(tabPage);
        }

        public void SaveEachContext()
        {
            foreach (TabPage tabPage in tabControl.TabPages)
            {
                saveTab(tabPage);
            }
        }

        private void saveTab(TabPage tabPage)
        {
            if (!tabToAbstractFile[tabPage].Save(tabToTextBox(tabPage).Text))
                return;
            if (wasChanged[tabPage])
            {
                wasChanged[tabPage] = false;
                tabPage.Text = tabPage.Text.Substring(0, tabPage.Text.Length - 1);
            }
        }

        private TextBox tabToTextBox(TabPage tabPage) 
        {
            if (tabPage == null)
                return null;
            else
                return (TextBox)(tabPage.Controls.Find("textBox", false)[0]);
        }

        private TabPage makeTabPage(String headline, Control box)
        {
            TabPage tabPage = new TabPage(headline);
            tabPage.Controls.Add(box);
            return tabPage;
        }

        private Control makeTextBox(AbstractFile file)
        {
            TextBox box = new TextBox();
            box.Name = "textBox";
            box.Multiline = true;
            box.Font = new System.Drawing.Font("courier", 10);
            box.ScrollBars = ScrollBars.Vertical;
            box.Dock = DockStyle.Fill;
            box.Text = file.Load();

            box.KeyUp += textBox_KeyUp;
            box.TextChanged += textBox_TextChanged;
            box.KeyDown += textBox_KeyDown;

            return box;
        }

        private void textBox_KeyDown(object sender, KeyEventArgs e)
        {
            // Ctrl + BACKSPACE
            if (e.KeyCode == Keys.Back && e.Control)
            {
                e.SuppressKeyPress = true;
                TextBox box = (TextBox)sender;
                int end = box.SelectionStart;
                if (end == 0) 
                    return;
                int start = box.Text.LastIndexOfAny(new char[] { ' ', '<', '=', '"', '\'', '\n', '\r', '\t' }, end - 1, end);
                if (start < 0)
                    start = 0;
                box.Text = box.Text.Remove(start, end - start);
                box.SelectionStart = start;
            }
            KeyDown.Invoke(sender, e);
        }

        private void textBox_KeyUp(object sender, KeyEventArgs e)
        {
            KeyUp.Invoke(sender, e);
        }

        private void textBox_TextChanged(object sender, EventArgs e)
        {
            TabPage page = (TabPage)((TextBox)sender).Parent;
            if (!wasChanged[page])
            {
                wasChanged[page] = true;
                page.Text = page.Text + "*";
            }
            TextChanged.Invoke(sender, e);
        }

        private void tabControl_Selected(object sender, EventArgs e)
        {
            TextChanged.Invoke(CurrentTextBox, null);
        }
    }
}
